import os

from report_type_enum import ReportType
from typing import List, Dict, Union, Optional
import re
import pandas as pd
import matplotlib.pyplot as plt

from src.excel_processor import Type1Strategy, Type2Strategy
from src.write_excel_report_data import WriteReportEntity


class ReadReportEntity:
    def __init__(self,
                 report_type: ReportType,
                 position_no: str,
                 position_nos: List[str],
                 description: str,
                 nominal: float,
                 unit: str,
                 usl: float,
                 lsl: float,
                 cavities: List[Union[float, str]],
                 table_cavities: List[List[Union[float, str]]],
                 has_red: bool):
        self.position_no = position_no
        self.position_nos = list(set(position_nos))  # 自动去重
        self.report_type = report_type
        self.description = description
        self.nominal = nominal
        self.unit = unit
        self.usl = usl
        self.lsl = lsl
        self.cavities = cavities
        self.table_cavities = table_cavities
        self.has_red = has_red
        self.strategy = self._get_strategy()

    def _get_strategy(self):
        return {
            ReportType.TYPE_1: Type1Strategy(),
            ReportType.TYPE_2: Type2Strategy()
        }.get(self.report_type, Type1Strategy())

    def execute_logic(self, config) -> WriteReportEntity:
        return self.strategy.execute(config, self)

    def export_red_report(self, output_folder: str):
        """导出红色标记报告"""
        if not self.has_red:
            return

        # 创建数据框架
        df = pd.DataFrame(columns=[
            'Position', 'Description', 'Nominal',
            'Unit', 'USL', 'LSL', *[f'Cav{i + 1}' for i in range(len(self.table_cavities[0]))]
        ])

        # 填充数据
        for idx, pos in enumerate(self.position_nos):
            row_data = {
                'Position': pos,
                'Description': self.description,
                'Nominal': self.nominal,
                'Unit': self.unit,
                'USL': self.usl,
                'LSL': self.lsl
            }
            # 填充腔号数据
            for i, val in enumerate(self.table_cavities[idx]):
                row_data[f'Cav{i + 1}'] = val
            df = pd.concat([df, pd.DataFrame([row_data])], ignore_index=True)

        # 生成文件路径
        output_path = os.path.join(output_folder, ""f"RED_{self.position_no}.xlsx")
        img_path = os.path.join(output_folder, f"RED_{self.position_no}.jpg")

        # 保存Excel
        df.to_excel(output_path, index=False)

        # 转换表格为图片
        self._dataframe_to_image(df, img_path)

        return img_path

    @staticmethod
    def _dataframe_to_image(df, img_path):
        """将DataFrame转换为图片"""
        plt.switch_backend('Agg')  # 防止GUI警告
        fig = plt.figure(figsize=(12, df.shape[0] * 0.5))
        ax = fig.add_subplot(111)
        ax.axis('off')

        # 创建表格
        table = plt.table(
            cellText=df.values,
            colLabels=df.columns,
            loc='center',
            cellLoc='center'
        )

        # 调整样式
        table.auto_set_font_size(False)
        table.set_fontsize(10)
        table.scale(1.2, 1.2)

        # 保存图片
        plt.savefig(img_path, bbox_inches='tight', dpi=300)
        plt.close()


def _parse_cavities(raw_data: List[str]) -> List[Union[float, str]]:
    processed = []
    for item in raw_data:
        item = str(item).strip()
        try:
            processed.append(float(item))  # 尝试转换为数字
        except ValueError:
            processed.append(item)  # 非数字保留为字符串
    return processed


def _get_parent_position(position_no: str) -> Optional[str]:
    """获取父位置（优先-pin处理）"""
    position_no = position_no.upper()
    for sep in ["-PIN", "-"]:
        if sep in position_no:
            return position_no.split(sep)[0]
    return None


def _update_entity_type(entity: ReadReportEntity):
    """类型升级规则（存在非数字时升级为TYPE_2）"""
    if any(isinstance(x, str) for x in entity.cavities):
        entity.report_type = ReportType.TYPE_2
        entity.strategy = Type2Strategy()


class BaseDataProcessor:
    def __init__(self):
        self.parent_map: Dict[str, ReadReportEntity] = {}
        self.final_entities: List[ReadReportEntity] = []

    # 预编译正则表达式提升性能
    FLOAT_PATTERN = re.compile(r'^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$')

    def _is_convertible(self, s: str) -> bool:
        return bool(self.FLOAT_PATTERN.fullmatch(str(s).strip())) if s else False

    def _process_child(self, parent_pos: str, row: list, has_red: bool):
        """处理子项合并逻辑"""
        position_no = str(row[1]).strip()
        cavities = _parse_cavities(row[7:])

        if parent_pos in self.parent_map:
            parent = self.parent_map[parent_pos]
            # 合并位置号（去重）
            if position_no not in parent.position_nos:
                parent.position_nos.append(position_no)
            # 合并数据
            parent.cavities.extend(cavities)
            parent.table_cavities.append(cavities)
            # 合并红色标记
            parent.has_red = parent.has_red or has_red
        else:
            parent = ReadReportEntity(
                report_type=ReportType.TYPE_1,
                position_no=parent_pos,
                position_nos=[position_no],
                description=str(row[2]).strip(),
                nominal=float(row[3]),
                unit=str(row[4]).strip(),
                usl=float(row[5]),
                lsl=float(row[6]),
                cavities=cavities,
                table_cavities=[_parse_cavities(row[7:])],
                has_red=has_red
            )
            self.parent_map[parent_pos] = parent
            self.final_entities.append(parent)

        _update_entity_type(parent)

    def process_row(self, row: list):
        try:
            has_red = bool(row[0])
            position_no = str(row[1]).strip()

            if not position_no:
                print(f"跳过空位置行: {row}")
                return

            # 处理带分隔符的情况
            if parent_pos := _get_parent_position(position_no):
                self._process_child(parent_pos, row, has_red)
            else:
                # 处理独立位置
                cavities = _parse_cavities(row[7:])
                entity = ReadReportEntity(
                    report_type=ReportType.TYPE_1,
                    position_no=position_no,
                    position_nos=[position_no],
                    description=str(row[2]).strip(),
                    nominal=float(row[3]),
                    unit=str(row[4]).strip(),
                    usl=float(row[5]),
                    lsl=float(row[6]),
                    cavities=cavities,
                    table_cavities=[cavities],
                    has_red=has_red
                )
                _update_entity_type(entity)
                self.final_entities.append(entity)

        except Exception as e:
            print(f"数据处理异常: {e}\n问题行: {row}")

    def convent_report_data(self, data: List[List]) -> List[ReadReportEntity]:

        for row in data[2:]:
            self.process_row(row)

        return self.final_entities
